package protocol.channels.control;

import protocol.control.Packet;

public class Handshake {
	
	/**
	 * Assembles a SYN packet for the three-way handshake
	 * @return The SYN packet
	 */
	public static Packet getHandshakeSynPacket() {
		Packet synPacket = new Packet();
		synPacket.setType((byte)0); // type 0 -> connection initialization / shutdown
		byte flags = 0;
		flags |= (1 << 7); // flags is now 1000 0000 (MSB = 1 -> connection initialization)
		flags |= (1 << 6); // flags is now 1100 0000 (7th bit = 1 -> SYN)
		synPacket.setFlags(flags);
		synPacket.setData(null);
		return synPacket;
	}
	
	/**
	 * Checks is the given packet a SYN packet
	 * @param packet The packet to be checked
	 * @return True if the packet is a SYN packet, false otherwise
	 */
	public static boolean isHandshakeSynPacket(Packet packet) {
		if (packet == null) return false;
		if (packet.getType() == 0) {
			if (packet.getData() != null) return false;
			/**
			 * (hex) 0xC0 = 1100 0000 (bin)
			 */
			return packet.getFlags() == ((byte)0xC0);
		} else {
			return false;
		}
	}

	/**
	 * Assembles an ACK packet for the three-way handshake
	 * @return The ACK packet
	 */
	public static Packet getHandshakeAckPacket() {
		Packet ackPacket = new Packet();
		ackPacket.setType((byte)0); // type 0 -> connection initialization / shutdown
		byte flags = 0;
		flags |= (1 << 7); // flags is now 1000 0000 (MSB = 1 -> connection initialization)
		flags |= (1 << 5); // flags is now 1010 0000 (6th bit = 1 -> ACK)
		ackPacket.setFlags(flags);
		ackPacket.setData(null);
		return ackPacket;
	}
	
	/**
	 * Checks is the given packet an ACK packet
	 * @param packet The packet to be checked
	 * @return True if the given packet was an ACK packet, false otherwise
	 */
	public static boolean isHandshakeAckPacket(Packet packet) {
		if (packet == null) return false;
		if (packet.getType() == 0) {
			if (packet.getData() != null) return false;
			/**
			 * (hex) 0xA0 = 1010 0000 (bin)
			 */
			return packet.getFlags() == ((byte)0xA0);
		} else {
			return false;
		}		
	}
	
	/**
	 * Assembles a SYN/ACK packet for the three-way handshake
	 * @return The SYN/ACK packet
	 */
	public static Packet getHandshakeSynAckPacket() {
		Packet synAckPacket = new Packet();
		synAckPacket.setType((byte)0); // type 0 -> connection initialization / shutdown
		byte flags = 0;
		flags |= (1 << 7); // flags is now 1000 0000 (MSB = 1 -> connection initialization)
		flags |= (1 << 6); // flags is now 1100 0000 (7th bit = 1 -> SYN)
		flags |= (1 << 5); // flags is now 1110 0000 (6th bit = 1 -> ACK)
		synAckPacket.setFlags(flags);
		synAckPacket.setData(null);
		return synAckPacket;
	}

	/**
	 * Checks is the given packet an SYN/ACK packet
	 * @param packet The packet to be checked
	 * @return True if the given packet was a SYN/ACK packet, false otherwise
	 */
	public static boolean isHandshakeSynAckPacket(Packet packet) {
		if (packet == null) return false;
		if (packet.getType() == 0) {
			if (packet.getData() != null) return false;
			/**
			 * (hex) 0xE0 = 1110 0000 (bin)
			 */
			return packet.getFlags() == ((byte)0xE0);
		} else {
			return false;
		}		
	}

}
